package chess_protocol

import (
	"bytes"

	"gddgame.cc/galaxy/utils"
)

//go:generate msgp

type DetailType byte

const (
	_ DetailType = iota
	CreateDataDetail
	UpdateDataDetail
	MoveDataDetail
	DestroyDataDetail
	//CreateNodeDetail
	UpdateNodeDetail
	SendMessageDetail
)

const (
	InsertOperateExtend      int = 255 // set和sorted都是直接插入最后，list的index不会超过255，
	DeleteOperateExtend          = -1  // set和sorted都是比较后删除，list不允许删除，只能更新为nil
	BatchDeleteOperateExtend     = -3
)

type ChessMode byte

const (
	SingleChessMode ChessMode = iota
	LayerChessMode
)

type MessageInstance interface {
	SetMessage(message *Message)
}

//msgp:tuple UpdateExtend
type UpdateExtend struct {
	Index byte        `json:"index" msg:"index"`
	Key   int         `json:"key" msg:"key"`
	No    int         `json:"no" msg:"no"`
	Value interface{} `json:"value" msg:"value"`
}

//msgp:tuple UpdateListId
type UpdateListId struct {
	Key   int    `json:"index" msg:"index"`
	Logic bool   `json:"logic" msg:"logic"`
	Value string `json:"value" msg:"value"`
}

//msgp:tuple UpdateListNo
type UpdateListNo struct {
	Key   int  `json:"index" msg:"index"`
	Logic bool `json:"logic" msg:"logic"`
	Value int  `json:"value" msg:"value"`
}

//msgp:tuple UpdateListNode
type UpdateListNode struct {
	Key   int    `json:"index" msg:"index"`
	Logic bool   `json:"logic" msg:"logic"`
	Value []byte `json:"value" msg:"value"`
}

//msgp:tuple UpdateProp
type UpdateProp struct {
	Key   byte        `json:"key" msg:"key"`
	Value interface{} `json:"value" msg:"value"`
}

//msgp:tuple ResetExtend
type ResetExtend struct {
	Index byte         `json:"index" msg:"index"`
	List  []ExtendItem `json:"list" msg:"list"`
}

//msgp:tuple ExtendItem
type ExtendItem struct {
	No    int         `json:"no" msg:"no"`
	Value interface{} `json:"value" msg:"value"`
}

//msgp:tuple Data
type Data struct {
	Range    uint16         `json:"range" msg:"range"`
	Position []byte         `json:"position" msg:"position"`
	Props    []interface{}  `json:"props" msg:"props"`
	Extend   [][]ExtendItem `json:"extend" msg:"extend"`
	ListId   [][]string     `json:"list_id" msg:"list_id"`
	ListNo   [][]int        `json:"list_no" msg:"list_no"`
	ListNode [][][]byte     `json:"list_node" msg:"list_node"`
	Message  *Message       `json:"message" msg:"message"`
}

func (data *Data) SendMessage(message *Message) {
	if message != nil && message.Persistent {
		data.Message = message
	}
}

func (data *Data) UpdateProp(props []UpdateProp) {
	if props != nil {
		for _, prop := range props {
			//fmt.Println(prop)
			if int(prop.Key) >= len(data.Props) {
				data.Props = append(data.Props, make([]interface{}, int(prop.Key)-len(data.Props)+1)...)
			}
			data.Props[prop.Key] = prop.Value
		}
	}
}
func (data *Data) ResetExtend(list []ResetExtend) {
	if list != nil {
		for _, operate := range list {
			if int(operate.Index) >= len(data.Extend) {
				data.Extend = append(data.Extend, make([][]ExtendItem, int(operate.Index)-len(data.Extend)+1)...)
			}
			data.Extend[operate.Index] = operate.List
		}
	}
}
func (data *Data) UpdateExtend(list []UpdateExtend) {
	if list != nil {
		for _, operate := range list {
			if int(operate.Index) >= len(data.Extend) {
				data.Extend = append(data.Extend, make([][]ExtendItem, int(operate.Index)-len(data.Extend)+1)...)
			}
			l := data.Extend[operate.Index]
			if operate.Key == InsertOperateExtend {
				l = append(l, ExtendItem{
					No:    operate.No,
					Value: operate.Value,
				})
				data.Extend[operate.Index] = l
				continue
			} else if operate.Key == DeleteOperateExtend {
				i := -1
				if operate.No > 0 {
					for index := range l {
						if l[index].No == operate.No {
							i = index
							break
						}
					}
				} else if operate.Value != nil {
					cc := utils.ToBytes(operate.Value)
					for index, b := range l {
						bb := utils.ToBytes(b.Value)
						if bytes.Equal(cc, bb) {
							i = index
							break
						}
					}
				}
				if i >= 0 {
					l = append(l[0:i], l[i+1:]...)
					data.Extend[operate.Index] = l
				}
				continue
			} else if operate.Key == BatchDeleteOperateExtend {
				data.Extend[operate.Index] = data.Extend[operate.Index][0:0]
				for index := range l {
					if l[index].No <= operate.No {
						continue
					}
					data.Extend[operate.Index] = append(data.Extend[operate.Index], l[index])
				}

			} else if operate.Key >= len(l) {
				l = append(l, make([]ExtendItem, operate.Key-len(l)+1)...)
				data.Extend[operate.Index] = l
			}
			l[operate.Key] = ExtendItem{
				No:    operate.No,
				Value: operate.Value,
			}
		}
	}
}
func (data *Data) UpdateListId(beDependents []UpdateListId) {
	if beDependents != nil {
		for _, operate := range beDependents {
			if operate.Key >= len(data.ListId) {
				data.ListId = append(data.ListId, make([][]string, operate.Key-len(data.ListId)+1)...)
			}
			if data.ListId[operate.Key] == nil {
				data.ListId[operate.Key] = []string{}
			}
			if operate.Logic {
				data.ListId[operate.Key], _ = utils.AddString(data.ListId[operate.Key], operate.Value)
			} else {
				data.ListId[operate.Key], _ = utils.RemoveString(data.ListId[operate.Key], operate.Value)
			}
		}
	}
}
func (data *Data) UpdateListNo(beDependents []UpdateListNo) {
	if beDependents != nil {
		for _, operate := range beDependents {
			if operate.Key >= len(data.ListNo) {
				data.ListNo = append(data.ListNo, make([][]int, operate.Key-len(data.ListNo)+1)...)
			}
			if data.ListNo[operate.Key] == nil {
				data.ListNo[operate.Key] = []int{}
			}
			if operate.Logic {
				data.ListNo[operate.Key], _ = utils.AddInt(data.ListNo[operate.Key], operate.Value)
			} else {
				data.ListNo[operate.Key], _ = utils.RemoveInt(data.ListNo[operate.Key], operate.Value)
			}
		}
	}
}
func (data *Data) UpdateListNode(ownNodes []UpdateListNode) {
	if ownNodes != nil {
		for _, operate := range ownNodes {
			if operate.Key >= len(data.ListNode) {
				data.ListNode = append(data.ListNode, make([][][]byte, operate.Key-len(data.ListNode)+1)...)
			}
			if data.ListNode[operate.Key] == nil {
				data.ListNode[operate.Key] = [][]byte{}
			}
			if operate.Logic {
				data.ListNode[operate.Key], _ = utils.AddBytes(data.ListNode[operate.Key], operate.Value)
			} else {
				data.ListNode[operate.Key], _ = utils.RemoveBytes(data.ListNode[operate.Key], operate.Value)
			}
		}
	}
}

//msgp:tuple SingleData
type SingleData struct {
	DataType byte        `json:"dataType" msg:"dataType"`
	Id       interface{} `json:"id" msg:"id"`
	Data     *Data       `json:"data" msg:"data"`
}

func (data *SingleData) SetMessage(message *Message) {
	data.Data.SendMessage(message)
}

//msgp:tuple UpdateData
type UpdateData struct {
	DataType byte             `json:"dataType" msg:"dataType"`
	Id       interface{}      `json:"id" msg:"id"`
	Data     UpdatePublicData `json:"data" msg:"data"`
}

//msgp:tuple UpdatePublicData
type UpdatePublicData struct {
	Props    []UpdateProp     `json:"props" msg:"props"`
	Reset    []ResetExtend    `json:"reset" msg:"reset"`
	Extend   []UpdateExtend   `json:"extend" msg:"extend"`
	ListId   []UpdateListId   `json:"list_id" msg:"list_id"`
	ListNo   []UpdateListNo   `jsoon:"list_no" msg:"list_no"`
	ListNode []UpdateListNode `json:"list_node" msg:"list_node"`
	Message  *Message         `json:"message" msg:"message"`
}

//msgp:tuple UpdateExtendTotal
type UpdateExtendTotal struct {
	Reset []ExtendItem   `json:"reset" msg:"reset"`
	List  []UpdateExtend `json:"list" msg:"list"`
}

func (upd *UpdatePublicData) ParseExtend() map[byte]*UpdateExtendTotal {
	m := make(map[byte]*UpdateExtendTotal)
	if upd.Reset != nil {
		for _, reset := range upd.Reset {
			if k, ok := m[reset.Index]; !ok {
				m[reset.Index] = &UpdateExtendTotal{
					Reset: reset.List,
				}
			} else {
				k.Reset = reset.List
			}
		}
	}
	if upd.Extend != nil {
		for _, extend := range upd.Extend {
			if k, ok := m[extend.Index]; !ok {
				m[extend.Index] = &UpdateExtendTotal{
					List: []UpdateExtend{extend},
				}
			} else {
				k.List = append(k.List, extend)
			}
		}
	}
	return m
}

//msgp:tuple MoveData
type MoveData struct {
	DataType byte             `json:"dataType" msg:"dataType"`
	Id       interface{}      `json:"id" msg:"id"`
	Data     UpdatePublicData `json:"data" msg:"data"`
	Current  []byte           `json:"current" msg:"current"`
	Position []byte           `json:"position" msg:"position"`
}

//msgp:tuple DestroyData
type DestroyData struct {
	DataType byte        `json:"dataType" msg:"dataType"`
	Id       interface{} `json:"id" msg:"id"`
}

//msgp:tuple UpdateNode
type UpdateNode struct {
	Range    uint16           `json:"range" msg:"range"`
	DataType byte             `json:"dataType" msg:"dataType"`
	Id       []byte           `json:"id" msg:"id"`
	Data     UpdatePublicData `json:"data" msg:"data"`
}

//msgp:tuple SendMessage
type SendMessage struct {
	DataType byte        `json:"dataType" msg:"dataType"`
	Id       interface{} `json:"id" msg:"id"`
	Message  *Message    `json:"message" msg:"message"`
}

//msgp:tuple Message
type Message struct {
	Range      uint16        `json:"range" msg:"range"`
	Event      byte          `json:"event" msg:"event"`
	Content    []byte        `json:"content" msg:"content"`
	Params     []interface{} `json:"params" msg:"params"`
	Persistent bool          `json:"persistent" msg:"persistent"`
}

func (message *Message) Copy() *Message {
	return &Message{
		Range:      message.Range,
		Event:      message.Event,
		Content:    message.Content,
		Params:     message.Params,
		Persistent: message.Persistent,
	}
}

//msgp:tuple DetailData
type DetailData struct {
	Type    DetailType `json:"type" msg:"type"`
	Content []byte     `json:"content" msg:"content"`
}

//msgp:tuple DataList
type DataList struct {
	MapNoId  string       `json:"mapNoId" msg:"mapNoId"`
	Size     int          `json:"size" msg:"size"`
	Position []byte       `json:"position" msg:"position"`
	Detail   []DetailData `json:"detail" msg:"detail"`
}

//msgp:tuple BlockData
type BlockData struct {
	MapNoId string       `json:"mapNoId" msg:"mapNoId"`
	Mode    ChessMode    `json:"mode" msg:"mode"`
	Sub     string       `json:"sub" msg:"sub"`
	Detail  []DetailData `json:"detail" msg:"detail"`
	Time    int64        `json:"time" msg:"time"`
}

//msgp:tuple CloseData
type CloseData struct {
	MapNoId string    `json:"mapNoId" msg:"mapNoId"`
	Mode    ChessMode `json:"mode" msg:"mode"`
}

//msgp:tuple ControlData
type ControlData struct {
}
